#include "widget.h"
#include "ui_widget.h"
#include <QThread>

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
  ui->setupUi(this);
  setWindowTitle("UDP组播接收端");
  // 接收组播消息
  connect( &m_udp,  & QUdpSocket::readyRead , this  ,  &Widget::slotReadyRead);

  //在QT5中存在
  //QAbstractSocket::error() 函数和 QUdpSocket::error同名
  //直接写会产出歧义，究竟是信号error 还是函数erro，所以不能这么写
  //connect(&m_udp , &QUdpSocket::error ,this ,&MainWindow::slotError);
  //而所有应 带上参数
  //  connect(&m_udp , SIGNAL(error(QAbstractSocket::SocketError)) ,this , SLOT(slotError(QAbstractSocket::SocketError)));
  //Qt6解决了这个问题，取消了error这个信号，改成了errorOccurred
  //connect(&m_udp , SIGNAL(errorOccurred(QAbstractSocket::SocketError)) ,this , SLOT(slotError(QAbstractSocket::SocketError)));
  connect(&m_udp , &QUdpSocket::errorOccurred ,this , [this](QAbstractSocket::SocketError err){slotError(err);});

}

Widget::~Widget() {
  delete ui;
}


void  Widget::slotReadyRead()
{
    qDebug()<<"接收组播数据线程"<<QThread::currentThread();
    //是否有数据抵达
    while ( m_udp.hasPendingDatagrams())
    {
        //获取要读取数据的大小
        int size = m_udp.pendingDatagramSize();

        //定义一块缓冲区，来接收数据
        QByteArray arr;
        arr.resize(size);

        QHostAddress  addr; //发送方的IP
        quint16  port;//发送方的端口

        //接收数据的同时，获取到对方的IP与端口
        int ret = m_udp.readDatagram(arr.data(),size, &addr,&port);
        if(ret > 0)
        {
            Message message(arr);
            if(!message.isHeartMessage()){
                QHostAddress  ipv4 (addr.toIPv4Address());
                QString str = QString("接收到%1:%2的组播消息: %3")
                        .arg(ipv4.toString()).arg(port).arg(message.getMessage());
                showMessage(str);
            }
        }

    }
}


 void Widget::slotError(QAbstractSocket::SocketError  err)
 {
     //枚举类型转为字符串、方便观测
   QString  strErr = QMetaEnum::fromType<QAbstractSocket::SocketError>().valueToKey( err );
   QString str =QString("错误码：%1   描述： %2").arg( strErr ).arg(  m_udp.errorString() ) ;
   showMessage( str );
 }

void Widget::showMessage(const QString &info) {
  ui->messageShoxEdit->appendPlainText(info);

}

void Widget::on_btnSend_clicked() {
  QString text = ui->messageEdit->text();
  Message msg(text);
  QString ip = ui->lineEditIP->text();
  uint multicastPort = ui->lineEditPort->text().toUInt();
  QHostAddress multicastAddress(ip);
  m_udp.writeDatagram(msg.toByteArray(),  multicastAddress, multicastPort);

}

void Widget::on_btnMultica_clicked()
{
  QString ip = ui->lineEditIP->text();
  uint multicastPort = ui->lineEditPort->text().toUInt();
  //必须先绑定，在加入组播
  if(!m_bind){
        bool rel = m_udp.bind( QHostAddress::AnyIPv4, multicastPort,QUdpSocket::ShareAddress);
         showMessage(rel?"绑定成功!":"绑定失败!");
        m_bind = true;
  }

  if(!m_join){
        // 加入组播, IP应为组播地址，否则就不是组播
     bool rel = m_udp.joinMulticastGroup(QHostAddress(ip));
     if(rel){
        ui->btnMultica->setText("离开组播");
        m_join = rel;
        showMessage("加入组播成功!");
     }else{
        showMessage("加入组播失败!");
     }
  }else{
     bool rel =  m_udp.leaveMulticastGroup(QHostAddress(ip));
     if(rel){
        ui->btnMultica->setText("加入组播");
        m_join = false;
        showMessage("离开组播成功!");
     }else{
        showMessage("离开组播失败!");
     }
  }



}

